package empe;

import java.util.Random;

/**
 * Gere uma concretizacao da classe Evento.
 */
public class Reproducao extends Evento {


	public Reproducao(int t_actual, Individuo indiv) {
		individuo = indiv;
		tempo = t_actual + calcular_tempo() + 1;
	}

	
	/**
	 * Gera uma observacao da variavel aleatoria
	 * @return valor (int) da observacao da variavel aleatoria
	 */
	protected int calcular_tempo() {
		Random random = new Random();
		double rand = random.nextDouble();

		return (int) Math.round(Math.abs(1-Math.log(individuo.ler_conforto())*Controlo.ler_ro()*Math.log(1.0-rand)));
	}

	
	
	/**
	 * Cria a nova matriz, copiando a do pai e realizando uma permutacao nas tarefas 
	 * (recorre a' funcao calc_nums_aleatorios_nao_repetidos),
	 * e o novo individuo, usando a funcao criar_individuo, de seguida,
	 * actualiza o seu tempo para que o objecto seja aproveitado para novo agendamento.
	 * @return a sua propria referencia.
	 */
	protected Evento simular() {
		
		int[][] matriz_controlo = Controlo.ler_C();
		int[][] matrix = new int[Controlo.ler_n()][Controlo.ler_m()];
		int[][] matriz = individuo.ler_matriz();
		int max_tarefas_a_alterar = (int) Math.floor((1-individuo.ler_conforto())*Controlo.ler_m());
		int[] vector_numero_tarefas_a_alterar = new int[max_tarefas_a_alterar];
		int i,j, rand, tarefa;
		int jmax = Controlo.ler_n();
		Random random = new Random();
		
		
		/*Copia a matriZ para matriX*/
		for(i=0; i < Controlo.ler_n(); i++) {
			for(j=0; j < Controlo.ler_m(); j++) {
				matrix[i][j] = matriz[i][j];
			}
		}
		
		calc_nums_aleatorios_nao_repetidos(vector_numero_tarefas_a_alterar);
		
		/*reordena as tarefas pelos processadores*/
		for(i=0; i < vector_numero_tarefas_a_alterar.length; i++) {
			tarefa = vector_numero_tarefas_a_alterar[i];
			for(j=0; j < jmax;j++) { /*anda nos cpus*/
			matrix[j][tarefa] = 0;	
			}
			rand = random.nextInt(jmax);
			matrix[rand][tarefa] = matriz_controlo[rand][tarefa];
		}
		
		
		/*cria e insere o individuo*/
		Controlo.lista_individuo.criar_individuo(matrix,this.tempo);

		

		/*actualiza o seu tempo e segue para o simulador*/
		this.tempo = this.tempo + calcular_tempo(); 
		
		return this;
	}
	
	
	
	/**
	 * Gera numeros aleatorios inteiros, entre zero e o numero de colunas da matriz C,
	 * ate preencher o vector passado por argumento.
	 * Gera sempre o menor numero de valores aleatoriamente, ie, quando se quer mais numeros 
	 * do que metade das colunas, geram-se aleatoriamente os numeros que nao se quer,
	 * mas o vector devolvido tem, sempre, os numeros validos.
	 */
	protected void calc_nums_aleatorios_nao_repetidos(int[] vector) {
		
		int i,j,k=0;
		int jmax = Controlo.ler_m();
		
		Random random = new Random();
		int rand;
		boolean valido = true;
		
		
		
		if(vector.length > jmax/2) { /* gerar os numeros que ñ são válidos*/
			/*guarda todos os nao validos*/
			int[] vector_aux = new int[jmax-vector.length];
			
			
			while(k < vector_aux.length) {
				valido = true;
				rand = random.nextInt(jmax);			
				for(i=0; i < k; i++) {
					if(vector_aux[i] == rand)
						valido = false;
				}
				if(valido == true) {
					vector_aux[k] = rand;
					k++;
				}
				
			}/*while*/
			
			/*agora gera-se o vector com os numeros validos, percorrendo todos os possiveis e
			 * não considerando os que se encontram no vector_aux
			 */
			k=0;
			for(i=0; i < vector.length; i++)
				for(j=0; j < vector_aux.length; j++ )
					if(i != vector_aux[j]) 
						valido = true;
					else
						valido = false;
			if(valido = true) {
				vector[k] = i;
				k++;
			}
				
								
			
		}
		else { /*gerar os numeros que são válidos*/
				
			while(k < vector.length) {
				valido = true;
				rand = random.nextInt(jmax);
				for(i=0; i < k; i++) {
					if(vector[i] == rand)
						valido = false;
				}
				if(valido == true) {
					vector[k] = rand;
					k++;
				}
				
			}/*while*/
			
		}/*else*/
		
	}/*função*/

}
